from src.storage.pso import PSO
from src.game.block.handler import BlockHandler
from src.game.entity.handler import EntityHandler
from src.handler.talent import TalentHandler
from src.handler.buff import BuffHandler

from src.game.entity.player import EntityPlayer
from src.game.entity.mob import EntityMob
from src.game.entity.fx import EntityFX
from src.game.entity.item import EntityItem
from src.game.entity.bullet import EntityBullet
from src.game.entity.rocket import EntityRocket
from src.game.entity.projectile import EntityProjectile
from src.game.entity.arrow import EntityArrow
from src.game.entity.obstacle import EntityObstacle
from src.game.entity.powerup import PowerUp
from src.game.entity.healup import HealUp

from src.game.buff.armor import ArmorBuff
from src.game.buff.speed import SpeedBuff

from src.game.talent.archer import ARCHER, ArcherTalent
from src.game.talent.none import NONE, NoneTalent
from src.game.talent.mage import MAGE, MageTalent
from src.helper.movement import MovementHelper
from src.handler.event import EventHandler
from src.event.world import EntityRegistryEvent, WorldUpdateEvent, WorldLoadEvent
from src.event.entity import EntitySpawnEvent, EntityDespawnEvent, EntityFXSpawnEvent
import pymunk

class World:

    def __init__(self, parent, data):
        self.parent = parent
        self.space = pymunk.Space()
        self.space.damping = 0.0
        self.space.add_collision_handler(0, 0, None, None, self.handleCollision)
        self.data = data
        self.blocks = []
        self.player = None
        self.entities = []
        self.register()
        self.readFromPSO(data)
        EventHandler.post(WorldLoadEvent(self))


    def update(self):
        for entity in self.entities:
            entity.update()
        EventHandler.post(WorldUpdateEvent(self))
        self.space.step(1./60.)
        
    def spawnEntity(self, entity):
        EventHandler.post(EntitySpawnEvent(entity))
        entity.world = self
        entity.onSpawn()
        self.entities.append(entity)
        
    def addEffect(self, entity, x, y):
        if isinstance(entity, EntityFX):
            entity.world = self
            entity.x = x
            entity.y = y
            EventHandler.post(EntityFXSpawnEvent(entity))
            entity.onSpawn()
            self.entities.append(entity)
        else:
            print("can't add effect with the name " + entity.name)
        
    def despawnEntity(self, entity):
        EventHandler.post(EntityDespawnEvent(entity))
        entity.onDespawn()
        self.entities.remove(entity)
        del entity

    def handleCollision(self, space, arbiter, *args, **kwargs):
        shape1, shape2 = arbiter.shapes
        shape1.entity.onCollision(shape2.entity)
        shape2.entity.onCollision(shape1.entity)
        return True

    def getPlayer(self):
        return self.player

    def getEntityByID(self, id):
        for entity in self.entities:
            if entity.id == id:
                return entity

    def getEntitiesInRect(self, box):
        entities = []
        for entity in self.entities:
            for ebox in entity.getBoundingBoxes():
                data = [ebox[0] + entity.x, ebox[1] + entity.y, ebox[2], ebox[3]]
                if MovementHelper.intersect(box, data):
                    entities.append(entity)
                    break
        return entities

    def getBlockAt(self, x, y):
        for block in self.blocks:
            if block.x == int(x) and block.y == int(y):
                return block

    def readFromPSO(self,data):

        for blockData in data.get("blocks"):
            blockPSO = PSO(blockData)
            block = BlockHandler.get(blockPSO.type).loadFromPSO(blockPSO)
            self.blocks.append(block)
        for entity in data.get("entities"):
            entityData = PSO(entity)
            print(entityData.type)
            entityObj = EntityHandler.get(entityData.type)
            entityObj.readFromPSO(entityData)
            entityObj.world = self
            entityObj.onLoad()
            self.entities.append(entityObj)
            if entityData.type == "entityplayer":
                print("add player")
                self.player = entityObj


    def writeToPSO(self, data):
        blockData = []
        for block in self.blocks:
            psoData = PSO()
            block.writeToPSO(psoData)
            blockData.append(psoData.getData())
        entityData = []
        for entity in self.entities:
            psoData = PSO()
            entity.writeToPSO(psoData)
            entityData.append(psoData.getData())
        data.set("blocks",blockData)
        data.set("entities",entityData)

    def register(self):
        EntityHandler.register(EntityPlayer)
        EntityHandler.register(EntityMob)
        EntityHandler.register(EntityProjectile)
        EntityHandler.register(EntityFX)
        EntityHandler.register(EntityItem)
        EntityHandler.register(EntityBullet)
        EntityHandler.register(EntityRocket)
        EntityHandler.register(EntityArrow)
        EntityHandler.register(EntityObstacle)
        EntityHandler.register(PowerUp)
        EntityHandler.register(HealUp)
        
        EventHandler.post(EntityRegistryEvent())
        
        BuffHandler.register(ArmorBuff)
        BuffHandler.register(SpeedBuff)
        
        TalentHandler.register(ARCHER, ArcherTalent)
        TalentHandler.register(NONE, NoneTalent)
        TalentHandler.register(MAGE, MageTalent)
